#include "../../config.h"

#include <glibmm/i18n.h>

#include "../application.h"
#include "../mainwindow.h"
#include "p_favorite.h"
#include "p_macros.h"

#include "../gtkversion.h"

namespace gpyp {
namespace pref {

//========================
class WordEditDialog : public TextEditorDialog {
private:
  Gtk::Entry &entry_;

protected:
  virtual void on_response(int response_id) {
    if (response_id == Gtk::RESPONSE_OK) {
      entry_.set_text(get_text());
    }
    Gtk::Dialog::on_response(response_id);
  }

public:
  void show() {
    TextEditorDialog::show();
    set_text(entry_.get_text());
  }

  WordEditDialog(Application &app, Gtk::Window &parent, Gtk::Entry &entry) :
    TextEditorDialog(app, parent),
    entry_          (entry)
  {
  }
};

//========================
class RegexEscapeDialog : public Gtk::Dialog {
private:
  Gtk::Entry entry_from_;
  Gtk::Entry entry_to_;

  void entry_from_on_changed() {
    entry_to_.set_text(Regex::escape(entry_from_.get_text()));
  }

public:
  RegexEscapeDialog(Gtk::Window &parent) :
    Gtk::Dialog(_("Regex escape"), parent)
  {
    entry_from_.signal_changed()
      .connect(sigc::mem_fun(*this, &RegexEscapeDialog::entry_from_on_changed));

    Gtk::VBox *vbox = get_vbox();
    vbox->pack_start(entry_from_, false, true);
    vbox->pack_start(entry_to_, false, true);

    add_button(Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE);
    show_all();
  }
};

//========================
// Rule
void Rule::word_on_changed() {
#ifdef GTK_ENTRY_HAS_ICON
  if (rule_->is_word_valid()) {
    gtk_entry_set_icon_from_pixbuf(word_.gobj(), GTK_ENTRY_ICON_SECONDARY, NULL);
  } else {
    word_.set_icon_from_stock(Gtk::Stock::DIALOG_ERROR, Gtk::ENTRY_ICON_SECONDARY);
  }
#else
  word_.modify_base(Gtk::STATE_NORMAL, (rule_->is_word_valid()
                                        ? Gtk::Entry::get_default_style()->get_base(Gtk::STATE_NORMAL)
                                        : Gdk::Color("red")));
#endif
}
void Rule::word_edit_on_clicked() {
  static DialogWrapper<WordEditDialog> dialog;
  if (!dialog) dialog.reset(new WordEditDialog(app_, parent_, word_));
  dialog->show();
}
void Rule::escape_on_clicked() {
  static DialogWrapper<RegexEscapeDialog> dialog;
  if (!dialog) dialog.reset(new RegexEscapeDialog(parent_));
  dialog->show();
}
void Rule::preset_on_clicked() {
  // Gdk::CURRENT_TIME
  preset_menu_.popup(1, GDK_CURRENT_TIME);
}

void Rule::set(RefRule rule) {
  unset();
  if (rule) {
    rule_ = rule;
    rule_->word()          ->attach(word_          .property_text());
    rule_->case_sensitive()->attach(case_sensitive_.property_active());
    rule_->invert()        ->attach(invert_        .property_active());
    rule_->target_name()   ->attach(target_name_   .property_active());
    rule_->target_genre()  ->attach(target_genre_  .property_active());
    rule_->target_desc()   ->attach(target_desc_   .property_active());
    rule_->target_comment()->attach(target_comment_.property_active());
    rule_->target_track()  ->attach(target_track_  .property_active());
    rule_->target_contact()->attach(target_contact_.property_active());
    rule_->target_ypname() ->attach(target_ypname_ .property_active());
    rule_->target_type()   ->attach(target_type_   .property_active());
    rule_->target_id()     ->attach(target_id_     .property_active());
    rule_->target_tip()    ->attach(target_tip_    .property_active());
    word_on_changed();
    conn_word_changed_ = rule_->word()->signal_changed()
      .connect(sigc::mem_fun(*this, &Rule::word_on_changed));
    set_sensitive(true);
  }
}
void Rule::unset() {
  if (!rule_) return;
  set_sensitive(false);
  conn_word_changed_.disconnect();
  if (rule_) {
    rule_->word()          ->detach(word_          .property_text());
    rule_->case_sensitive()->detach(case_sensitive_.property_active());
    rule_->invert()        ->detach(invert_        .property_active());
    rule_->target_name()   ->detach(target_name_   .property_active());
    rule_->target_genre()  ->detach(target_genre_  .property_active());
    rule_->target_desc()   ->detach(target_desc_   .property_active());
    rule_->target_comment()->detach(target_comment_.property_active());
    rule_->target_track()  ->detach(target_track_  .property_active());
    rule_->target_contact()->detach(target_contact_.property_active());
    rule_->target_ypname() ->detach(target_ypname_ .property_active());
    rule_->target_type()   ->detach(target_type_   .property_active());
    rule_->target_id()     ->detach(target_id_     .property_active());
    rule_->target_tip()    ->detach(target_tip_    .property_active());
    rule_.reset();
  }
}

Rule::Rule(Application &app, Gtk::Window &parent) :
  app_           (app),
  parent_        (parent),
  case_sensitive_("Aa"),
  invert_        ("!"),
  target_name_   (_("Name")),
  target_genre_  (_("Genre")),
  target_desc_   (_("Description")),
  target_comment_(_("Comment")),
  target_track_  (_("Track")),
  target_contact_(_("Contact")),
  target_ypname_ (_("YP name")),
  target_type_   (_("Type")),
  target_id_     (_("ID")),
  target_tip_    (_("TIP")),
  preset_menu_   (*this)
{
#ifdef GTK_HAVE_TOOLTIP
  word_          .set_tooltip_text(_("Regular expression only"));
  case_sensitive_.set_tooltip_text(_("Case sensitive"));
  invert_        .set_tooltip_text(_("Invert rule"));
#endif

  Gtk::Button *b_w = Gtk::manage(new Gtk::Button(Gtk::Stock::EDIT));
  Gtk::Button *b_e = Gtk::manage(new Gtk::Button(_("Escape")));
  Gtk::Button *b_p = Gtk::manage(new Gtk::Button(_("Preset")));
#define BUTTON_CONNECT(B, N)                                            \
  (B)->signal_clicked().connect(sigc::mem_fun(*this, &Rule::N##_on_clicked))
  BUTTON_CONNECT(b_w, word_edit);
  BUTTON_CONNECT(b_e, escape);
  BUTTON_CONNECT(b_p, preset);
#undef BUTTON_CONNECT

  Gtk::HBox *h1 = Gtk::manage(new Gtk::HBox(false, 2));
  h1->pack_start(word_);
  h1->pack_start(*b_w,            false, false);
  h1->pack_start(case_sensitive_, false, false);
  h1->pack_start(invert_,         false, false);
  h1->pack_start(*b_e,            false, false);
  h1->pack_start(*b_p,            false, false);
  pack_start(*h1, false, false);

  Gtk::Table *t1 = Gtk::manage(new Gtk::Table());
  t1->attach(target_name_,    0, 1, 0, 1);
  t1->attach(target_genre_,   1, 2, 0, 1);
  t1->attach(target_desc_,    2, 3, 0, 1);
  t1->attach(target_comment_, 0, 1, 1, 2);
  t1->attach(target_track_,   1, 2, 1, 2);
  t1->attach(target_contact_, 2, 3, 1, 2);
  t1->attach(target_ypname_,  0, 1, 2, 3);
  t1->attach(target_type_,    1, 2, 2, 3);
  t1->attach(target_id_,      0, 1, 3, 4);
  t1->attach(target_tip_,     1, 2, 3, 4);
  t1->set_col_spacings(2);
  t1->set_row_spacings(2);
  t1->set_border_width(2);
  Gtk::Frame *f1 = Gtk::manage(new Gtk::Frame(_("Targets")));
  f1->add(*t1);
  pack_start(*f1);
}
Rule::~Rule() {
  conn_word_changed_.disconnect();
}

//========================
// RuleCollection::Selector
void RuleCollection::Selector::on_cell_data(Gtk::CellRendererText *cell,
                                            const Gtk::TreeIter   &iter) {
  cell->property_text() = *get_item(iter)->word();
}

RuleCollection::Selector::Selector() {
}

//========================
// RuleCollection
void RuleCollection::on_selected(RefRule rule) {
  rule_.set(rule);
}

void RuleCollection::set(RefFavorite favorite) {
  unset();
  selector_.set(favorite);

  if (favorite) {
    favorite_ = favorite;
    favorite_->rule_or()     ->attach(or_     .property_active());
    favorite_->rule_age_min()->attach(age_min_.property_value());
    favorite_->rule_age_max()->attach(age_max_.property_value());
    set_sensitive(true);
  }
}
void RuleCollection::unset() {
  set_sensitive(false);
  selector_.unset();
  rule_.unset();

  if (favorite_) {
    favorite_->rule_or()     ->detach(or_     .property_active());
    favorite_->rule_age_min()->detach(age_min_.property_value());
    favorite_->rule_age_max()->detach(age_max_.property_value());
    favorite_.reset();
  }
}

RuleCollection::RuleCollection(Application &app, Gtk::Window &parent) :
  Gtk::VBox(false, 2),
  rule_    (app, parent),
  or_      (_("OR"))
{
  Gtk::ScrolledWindow *sw1 = Gtk::manage(new Gtk::ScrolledWindow());
  sw1->add(selector_);
  sw1->set_shadow_type(Gtk::SHADOW_IN);
  sw1->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  Gtk::HPaned *h1 = Gtk::manage(new Gtk::HPaned());
  h1->pack1(*sw1, false, true);
  h1->pack2(rule_, true, false);
  pack_start(*h1);

  Gtk::Button *b_u = Gtk::manage(new Gtk::Button(Gtk::Stock::GO_UP));
  Gtk::Button *b_d = Gtk::manage(new Gtk::Button(Gtk::Stock::GO_DOWN));
  Gtk::Button *b_a = Gtk::manage(new Gtk::Button(Gtk::Stock::ADD));
  Gtk::Button *b_r = Gtk::manage(new Gtk::Button(Gtk::Stock::REMOVE));
  b_u->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::up));
  b_d->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::down));
  b_a->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::add));
  b_r->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::remove));
  Gtk::HButtonBox *h2 =
    Gtk::manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 2));
  h2->pack_start(*b_u, false, false);
  h2->pack_start(*b_d, false, false);
  h2->pack_start(*b_a, false, false);
  h2->pack_start(*b_r, false, false);
  Gtk::HBox *h3 = Gtk::manage(new Gtk::HBox(false, 2));
  h3->pack_start(or_, false, false);
  h3->pack_start(*h2);
  pack_start(*h3, false, false);

  gtk_box_pack_start(GTK_BOX(gobj()), gtk_hseparator_new(), FALSE, FALSE, 0);

  SETUP_SPINBUTTON(age_min_, -1, 60000);
  SETUP_SPINBUTTON(age_max_, -1, 60000);
  Gtk::HBox *h4 = Gtk::manage(new Gtk::HBox(false, 2));
  h4->pack_start(age_min_);
  gtk_box_pack_start(GTK_BOX(h4->gobj()),
                     gtk_label_new(_("<= Age(min) <=")), TRUE, TRUE, 0);
  h4->pack_start(age_max_);
  pack_start(*h4, false, false);

  selector_.signal_selected()
    .connect(sigc::mem_fun(*this, &RuleCollection::on_selected));
}

//========================
// Favorite
void Favorite::select_font_on_clicked() {
  Gtk::FontSelectionDialog dialog;
  dialog.set_font_name(font_.get_text());
  if (dialog.run() == Gtk::RESPONSE_OK) {
    font_.set_text(dialog.get_font_name());
  }
}

void Favorite::set(RefFavorite favorite) {
  unset();
  rules_.set(favorite);
  if (favorite) {
    favorite_ = favorite;
    favorite_->name()  ->attach(name_  .property_text());
    favorite_->enable()->attach(enable_.property_active());
    favorite_->filter()->attach(filter_.property_active());

    bgcolor_.set(favorite_->bgcolor());
    fgcolor_.set(favorite_->fgcolor());
    favorite_->font()->attach(font_.property_text());
    sort_.set(favorite_->sort());

    ng_           .set(favorite_->ng());
    auto_play_    .set(favorite_->auto_play());
    auto_record_  .set(favorite_->auto_record());
    notify_new_   .set(favorite_->notify_new());
    notify_change_.set(favorite_->notify_change());
    notify_sound_ .set(favorite_->notify_sound(),
                       favorite_->notify_sound_volume());
    set_sensitive(true);
  }
}
void Favorite::unset() {
  set_sensitive(false);
  rules_.unset();
  if (favorite_) {
    favorite_->name()  ->detach(name_  .property_text());
    favorite_->enable()->detach(enable_.property_active());
    favorite_->filter()->detach(filter_.property_active());

    bgcolor_.unset();
    fgcolor_.unset();
    favorite_->font()->detach(font_.property_text());
    sort_.unset();

    ng_           .unset();
    auto_play_    .unset();
    auto_record_  .unset();
    notify_new_   .unset();
    notify_change_.unset();
    notify_sound_ .unset();
    favorite_.reset();
  }
}

Favorite::Favorite(Application &app,
                   Gtk::Window &parent,
                   RefFavorite  favorite) :
  Gtk::VBox     (false, 2),
  enable_       (_("Enable")),
  filter_       (_("Filter")),
  rules_        (app, parent),
  bgcolor_      (app, parent),
  fgcolor_      (app, parent),
  ng_           (_("NG")),
  auto_play_    (_("Auto play")),
  auto_record_  (_("Auto record")),
  notify_new_   (_("Notify new channels")),
  notify_change_(_("Notify change")),
  notify_sound_ (app, parent)
{
  Gtk::HBox *h1 = Gtk::manage(new Gtk::HBox(false, 2));
  gtk_box_pack_start(GTK_BOX(h1->gobj()),
                     gtk_label_new(_("Name")), FALSE, FALSE, 0);
  h1->pack_start(name_);
  h1->pack_start(enable_, false, false);
  h1->pack_start(filter_, false, false);
  pack_start(*h1, false, false);

  Gtk::Frame *f1 = Gtk::manage(new Gtk::Frame(_("Rule")));
  rules_.set_border_width(2);
  f1->add(rules_);
  pack_start(*f1, false, false);

  Gtk::Button *b_f = Gtk::manage(new Gtk::Button(Gtk::Stock::SELECT_FONT));
  b_f->signal_clicked()
    .connect(sigc::mem_fun(*this, &Favorite::select_font_on_clicked));

  Gtk::Table *t1 = Gtk::manage(new Gtk::Table());
  TABLE_LABEL(*t1, 0, _("Background"));
  TABLE_LABEL(*t1, 1, _("Text"));
  TABLE_LABEL(*t1, 2, _("Font"));
  TABLE_LABEL(*t1, 3, _("Sort"));
  t1->attach(bgcolor_,       1, 3, 0, 1);
  t1->attach(fgcolor_,       1, 3, 1, 2);
  t1->attach(font_,          1, 2, 2, 3);
  t1->attach(*b_f,           2, 3, 2, 3, Gtk::SHRINK | Gtk::FILL);
  t1->attach(sort_,          1, 3, 3, 4);
  t1->attach(ng_,            0, 3, 4, 5);
  t1->attach(auto_play_,     0, 3, 5, 6);
  t1->attach(auto_record_,   0, 3, 6, 7);
  t1->attach(notify_new_,    0, 3, 7, 8);
  t1->attach(notify_change_, 0, 3, 8, 9);
  TABLE_LABEL(*t1, 9, _("Notify sound"));
  t1->attach(notify_sound_,  1, 3, 9, 10);
  t1->set_col_spacings(2);
  t1->set_row_spacings(2);
  pack_start(*t1, false, false);

  set(favorite);
}

//========================
// FavoriteCollection::Selector
void FavoriteCollection::Selector::on_cell_data(Gtk::CellRendererText *cell,
                                                const Gtk::TreeIter   &iter) {
  cell->property_text() = *get_item(iter)->name();
}

FavoriteCollection::Selector::Selector(Application &app) :
  SelectorListView<gpyp::FavoriteCollection>(app.favcollection())
{
}

//========================
// FavoriteCollection
void FavoriteCollection::apply_on_clicked() {
  app_.ypcollection()->rematch_favorite();
  app_.mainwindow()->channellist()->resort();
  app_.mainwindow()->channellist()->refilter();
  app_.mainwindow()->channellist()->queue_draw();
}

FavoriteCollection::FavoriteCollection(Application &app,
                                       Gtk::Window &parent) :
  Gtk::VBox(false, 2),
  app_     (app),
  selector_(app_),
  favorite_(app_, parent)
{
  Gtk::ScrolledWindow *sw1 = Gtk::manage(new Gtk::ScrolledWindow());
  sw1->add(selector_);
  sw1->set_shadow_type(Gtk::SHADOW_IN);
  sw1->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  sw1->set_size_request(100, -1);

  Gtk::Button *b_u = Gtk::manage(new Gtk::Button(Gtk::Stock::GO_UP));
  Gtk::Button *b_d = Gtk::manage(new Gtk::Button(Gtk::Stock::GO_DOWN));
  Gtk::Button *b_a = Gtk::manage(new Gtk::Button(Gtk::Stock::ADD));
  Gtk::Button *b_r = Gtk::manage(new Gtk::Button(Gtk::Stock::REMOVE));
  Gtk::Button *b_p = Gtk::manage(new Gtk::Button(Gtk::Stock::APPLY));
  b_u->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::up));
  b_d->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::down));
  b_a->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::add));
  b_r->signal_clicked().connect(sigc::mem_fun(selector_, &Selector::remove));
  b_p->signal_clicked().connect(sigc::mem_fun(*this, &FavoriteCollection::apply_on_clicked));
  Gtk::HButtonBox *h1 =
    Gtk::manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 2));
  h1->pack_start(*b_u, false, false);
  h1->pack_start(*b_d, false, false);
  h1->pack_start(*b_a, false, false);
  h1->pack_start(*b_r, false, false);
  h1->pack_start(*b_p, false, false);
  Gtk::VBox *v1 = Gtk::manage(new Gtk::VBox(false, 2));
  v1->pack_start(favorite_);
  v1->pack_end(*h1, false, false);
  Gtk::HPaned *h2 = Gtk::manage(new Gtk::HPaned());
  h2->pack1(*sw1, false, true);
  h2->pack2(*v1,  true,  false);
  pack_start(*h2);

  selector_.select_first();
  favorite_.set(selector_.get_selected());
  selector_.signal_selected()
    .connect(sigc::mem_fun(favorite_, &Favorite::set));
}

}/*pref*/
}/*gpyp*/
